﻿using UnityEngine;
using System.Collections;

using agsXMPP;
using System;
using agsXMPP.protocol.client;
using System.Security.Cryptography;
using DICE_GS;
using System.Collections.Generic;
using System.Text;

public enum PresenceStatus : byte
{
    ONLINE,
    PLAYING,
    OFFLINE,
}

public class CXmppManager : MonoBehaviour
{
    float buttonSizeMultipier = (float)Screen.width / 800.0f;

    private static bool IsXmppManagerCreated = false;
    private static bool IsConnected = false;
    private static bool IsLoggedOn = false;

    private static int ReconnCount = 0;

    private static bool NeedReconnect = false;

    private static bool OnDebug = false;

    private XmppClientConnection xmppCli = new XmppClientConnection();

    private Dictionary<int, PresenceStatus> FriendsPresenceMap = new Dictionary<int, PresenceStatus>();

    private string ServerName
    {
        get
        {
            if (CSceneManager.BuildType == 1)
                return "lemontree-msvr"; //QA
            else if (CSceneManager.BuildType == 0)
                return "MGG-LEMONPUB01"; //DEV
            else
                return "MGG-LEMONPUB01"; //DEV
        }
    }

    private string ServerIP
    {
        get
        {
            if (CSceneManager.BuildType == 1)
                return "211.189.163.178"; //QA
            else if (CSceneManager.BuildType == 0)
                return "211.189.163.179"; //DEV
			else if( CSceneManager.BuildType == 2 )
				return  PlayerPrefs.GetString("CustomXmppServerAddress");
            else
                return "211.189.163.179"; //DEV
        }
    }

    private int DisconnTick = 0;

    private Queue<string> MsgQueue = new Queue<string>();

    void Awake()
    {
//#if UNITY_EDITOR
		gameObject.SetActive(false);
//#endif
        if (IsXmppManagerCreated)
        {
            Destroy(gameObject);
        }
        else
        {
            IsXmppManagerCreated = true;
            DontDestroyOnLoad(gameObject);
        }
    }

	// Use this for initialization
	void Start () {

        if (xmppCli != null)
        {
            xmppCli.OnLogin += xmppCli_OnLogin;
            xmppCli.OnBinded += xmppCli_OnBinded;
            xmppCli.OnAuthError += xmppCli_OnAuthError;
            xmppCli.OnClose += xmppCli_OnClose;
            xmppCli.OnXmppConnectionStateChanged += xmppCli_OnXmppConnectionStateChanged;
            xmppCli.OnMessage += xmppCli_OnMessage;
            xmppCli.OnError += xmppCli_OnError;
            xmppCli.OnIq += xmppCli_OnIq;
            xmppCli.OnWriteSocketData += xmppCli_OnWriteSocketData;
            xmppCli.OnReadSocketData += xmppCli_OnReadSocketData;
            xmppCli.OnSocketError += xmppCli_OnSocketError;
            xmppCli.OnPresence += xmppCli_OnPresence;
            xmppCli.OnRosterItem += xmppCli_OnRosterItem;

            xmppCli.Server = ServerName;
            xmppCli.ConnectServer = ServerIP;
            xmppCli.Resource = "Dice";

            xmppCli.KeepAlive = true;
            xmppCli.KeepAliveInterval = 60;
            xmppCli.AutoPresence = true;

            xmppCli.Username = "test";
            xmppCli.Password = "test";

            xmppCli.UseStartTLS = false;
            xmppCli.AutoResolveConnectServer = false; // option test

            //xmppCli.Open();
        }
	}

    void xmppCli_OnRosterItem(object sender, agsXMPP.protocol.iq.roster.RosterItem item)
    {
        if (OnDebug)
        {
            Debug.LogError(String.Format("XMPP : {0}", "xmppCli_OnRosterItem"));
            Debug.LogError(item.ToString());
        }
    }

    void xmppCli_OnPresence(object sender, Presence pres)
    {
        Debug.LogError(String.Format("XMPP : {0}", "xmppCli_OnPresence"));
        Debug.LogError(pres.ToString());

        if (pres.Type == PresenceType.available)
        {
            int UserDBID = 0;

            int.TryParse(pres.From.User, out UserDBID);

            if (UserDBID > 0)
            {
                if (!FriendsPresenceMap.ContainsKey(UserDBID))
                {
                    lock (FriendsPresenceMap)
                    {
                        if (pres.Show == ShowType.dnd)
                        {
                            FriendsPresenceMap.Add(UserDBID, PresenceStatus.PLAYING);
                        }
                        else
                        {
                            FriendsPresenceMap.Add(UserDBID, PresenceStatus.ONLINE);
                        }
                    }
                }
                else
                {
                    if (pres.Show == ShowType.dnd)
                    {
                        FriendsPresenceMap[UserDBID] = PresenceStatus.PLAYING;
                    }
                    else
                    {
                        FriendsPresenceMap[UserDBID] = PresenceStatus.ONLINE;
                    }
                }
            }
        }
        else if (pres.Type == PresenceType.unavailable)
        {
            int UserDBID = 0;

            int.TryParse(pres.From.User, out UserDBID);

            if (UserDBID > 0)
            {
                if (!FriendsPresenceMap.ContainsKey(UserDBID))
                {
                    lock (FriendsPresenceMap)
                    {
                        FriendsPresenceMap.Add(UserDBID, PresenceStatus.OFFLINE);
                    }
                }
                else
                {
                    FriendsPresenceMap[UserDBID] = PresenceStatus.OFFLINE;
                }
            }
        }
        else if(pres.Type == PresenceType.subscribe)
        {
            //Jid From = new Jid((string)pres.Attributes["from"]);
            xmppCli.PresenceManager.ApproveSubscriptionRequest(pres.From);
            xmppCli.PresenceManager.Subscribe(pres.From);
        }
        else if(pres.Type == PresenceType.unsubscribe)
        {
            Jid From = new Jid((string)pres.Attributes["from"]);
            xmppCli.PresenceManager.Unsubscribe(pres.From);
        }

        {
            int UserDBID = 0;

            int.TryParse(pres.From.User, out UserDBID);

            if (UserDBID > 0)
            {
                if (FriendsPresenceMap.ContainsKey(UserDBID))
                {
                    Debug.LogError(FriendsPresenceMap[UserDBID].ToString());
                }
            }
        }
    }
    void xmppCli_OnSocketError(object sender, Exception ex)
    {
        Debug.LogError(String.Format("XMPP : {0}", "xmppCli_OnSocketError"));
        Debug.LogError(ex.ToString());  
    }

    void xmppCli_OnReadSocketData(object sender, byte[] data, int count)
    {
        if (OnDebug)
        {
            Debug.LogError(String.Format("XMPP : {0}", "xmppCli_OnReadSocketData"));
            Debug.LogError(Encoding.Default.GetString(data, 0, count));
        }
    }

    void xmppCli_OnWriteSocketData(object sender, byte[] data, int count)
    {
        if (OnDebug)
        {
            Debug.LogError(String.Format("XMPP : {0}", "xmppCli_OnWriteSocketData"));
            Debug.LogError(Encoding.Default.GetString(data));
        }
    }

    void xmppCli_OnError(object sender, Exception ex)
    {
        Debug.LogError(String.Format("XMPP : {0}", "xmppCli_OnError"));
        Debug.LogError(String.Format("XMPP : {0}", ex.ToString()));
        
    }

    void xmppCli_OnIq(object sender, IQ iq)
    {
        if (OnDebug)
        {
            Debug.LogError(String.Format("XMPP : {0}", "xmppCli_OnIq"));
            Debug.LogError(String.Format("XMPP : {0}", iq.ToString()));
        }
    }

    void xmppCli_OnMessage(object sender, Message msg)
    {
        Debug.LogError(String.Format("XMPP : {0}", "xmppCli_OnMessage"));
        Debug.LogError(String.Format("XMPP : {0}", msg.Body));

        if (msg.Subject.Equals("DiceInvite"))
        {
            //Debug.LogError(String.Format("XMPP : {0}", msg.Body));

            MsgQueue.Enqueue(msg.Body);
        }
    }

    void xmppCli_OnXmppConnectionStateChanged(object sender, XmppConnectionState state)
    {
        if (OnDebug)
        {
            Debug.LogError(String.Format("XMPP : {0}", "xmppCli_OnXmppConnectionStateChanged"));
            Debug.LogError(String.Format("XMPP : {0}", state.ToString()));
        }

        if (state.ToString().Equals("Connected"))
        {
            IsConnected = true;
        }

        if (state.ToString().Equals("Disconnected"))
        {
            IsConnected = false;
        }

        ReconnCount = 0;
    }

    void xmppCli_OnClose(object sender)
    {
        Debug.LogError(String.Format("XMPP : {0}", "xmppCli_OnClose"));

        if (OnDebug)
        {
            Debug.LogError(String.Format("XMPP : {0}", "xmppCli_OnClose"));
        }

        if (xmppCli.RegisterAccount)
        {
            xmppCli.Open();
        }

        IsConnected = false;
        //IsLoggedOn = false;
    }

    void xmppCli_OnAuthError(object sender, agsXMPP.Xml.Dom.Element e)
    {
        if (OnDebug)
        {
            Debug.LogError(String.Format("XMPP : {0}", "xmppCli_OnAuthError"));
            Debug.LogError(String.Format("XMPP : {0}", e.FirstChild.TagName));
        }
        
        if (e.FirstChild.TagName.Equals("not-authorized"))
        {
            xmppCli.RegisterAccount = true;
            xmppCli.Close();
        }
    }

    void xmppCli_OnBinded(object sender)
    {
        if (OnDebug)
        {
            Debug.LogError(String.Format("XMPP : {0}", "xmppCli_OnBinded"));
        }

        IsLoggedOn = true;
    }

    void xmppCli_OnLogin(object sender)
    {
        Debug.LogError(String.Format("XMPP : {0}", xmppCli.MyJID));

        if (OnDebug)
        {
            Debug.LogError(String.Format("XMPP : {0}", "xmppCli_OnLogin"));
        }
    }
	
	// Update is called once per frame
	void FixedUpdate () {

        DisconnTick++;

        if (DisconnTick >= 150) // 대략 5초
        {
            DisconnTick = 0;

            if (CSceneManager.m_Scene != SCENE.LoadingScene && CSceneManager.m_Scene != SCENE.CharacterSelectScene && CSceneManager.m_Scene != SCENE.InGameScene && !CSceneManager.isReplay)
            {
                if (MyInfo.Instance.DBID > 0)
                {
                    //Debug.LogError("XmppConnectionState -- " + xmppCli.XmppConnectionState);

                    if (!xmppCli.Authenticated || !xmppCli.Binded)
                    {
                        xmppCli.Username = MyInfo.Instance.DBID.ToString();
                        xmppCli.Password = "lemontree";

                        if (xmppCli.XmppConnectionState == XmppConnectionState.Disconnected)
                        {
                            StartCoroutine("ConnectToServer");
                        }
                        else if (xmppCli.XmppConnectionState != XmppConnectionState.SessionStarted)
                        {
                            ReconnCount++;
                        }

                        if (ReconnCount >= 5)
                        {
                            xmppCli.Close();
                            ReconnCount = 0;
                        }
                    }
                }

                //if (xmppCli.XmppConnectionState == XmppConnectionState.SessionStarted)
                //{
                //    if (xmppCli.Show != ShowType.NONE)
                //    {
                //        xmppCli.Show = ShowType.NONE;
                //        xmppCli.SendMyPresence();
                //    }
                //}
            }

            if (CSceneManager.m_Scene == SCENE.PVP_MakeRoomScene21 || CSceneManager.m_Scene == SCENE.PvPMakeRoomScene || CSceneManager.m_Scene == SCENE.InGameScene)
            {
                if (xmppCli.XmppConnectionState == XmppConnectionState.SessionStarted)
                {
                    if (xmppCli.Show != ShowType.dnd)
                    {
                        xmppCli.Show = ShowType.dnd;
                        xmppCli.SendMyPresence();
                    }
                }
            }
            else
            {
                if (xmppCli.XmppConnectionState == XmppConnectionState.SessionStarted)
                {
                    if (xmppCli.Show != ShowType.NONE)
                    {
                        xmppCli.Show = ShowType.NONE;
                        xmppCli.SendMyPresence();
                    }
                }
            }
        }

        while (MsgQueue.Count > 0)
        {
            string msg = MsgQueue.Dequeue();

            Hashtable invite = JSON.JsonDecode(msg) as Hashtable;

            Type = Convert.ToByte(invite["Type"].ToString());
            roomName = invite["RoomId"].ToString();
            mapName = invite["MapName"].ToString();
            gameServerIpAddress = invite["Addr"].ToString();
            friendName = invite["From"].ToString();
            Int64 TimeStamp = Int64.Parse(invite["TimeStamp"].ToString());

            Int64 timeOffset = (System.DateTime.UtcNow.Ticks + CSceneManager.TimeOffset) - TimeStamp;
            //if (timeOffset < 30000f)
            {
                //if (!MessagePopup.window.isShowingPopup(MESSAGEPOPUPTYPE.ReceiveGameInviteFromFriend))
                //{
                string[] param = new string[1];
                param[0] = friendName;
                MessagePopup.window.ShowPopup(MESSAGEPOPUPTYPE.ReceiveGameInviteFromFriend, param, MessagePopupCallback);
                //}
            }
            //else
            //{
            //    Debug.LogError("30000!!!");
            //}
        }
	}

    private IEnumerator ConnectToServer()
    {
        xmppCli.Open();
        yield return null;
    }

    byte Type;
    string gameServerIpAddress = "";
    string roomName = "";
    string mapName = "";
    string friendName = "";
    public void MessagePopupCallback(MESSAGEPOPUPTYPE type, bool isYes)
    {
        if (isYes)
        {
            //redirect Join 처럼 처리

            if (!CSceneManager.NowNetworkSwitching)
            {
                Debug.LogError("Go Invite");
                CSceneManager.NowNetworkSwitching = true;
                CSceneManager.NeedToDisconnect = true;

                CNetworkManager.Instance.Disconnect();

                CSceneManager.manager.RequestRedirectJoin((byte)JoinType.JT_INVITE_JOIN, gameServerIpAddress, roomName, mapName, "", 0);
            }
            else
            {
                Debug.LogError("Go Invite!!!!!");
            }
        }
    }

	/*
    void OnGUI()
    {
        //if (CSceneManager.m_Scene == SCENE.MainScene)
        //{
        //    if (GUI.Button(new Rect(130f, 0f, 150 * buttonSizeMultipier, 30*buttonSizeMultipier), xmppCli.XmppConnectionState.ToString()))
        //    {
        //        ;
        //    }

        //    int Grade = 0;

        //    if(MyInfo.Instance.Score <= 900)
        //    {
        //        Grade = 1;
        //    }
        //    else if(MyInfo.Instance.Score <= 1100)
        //    {
        //        Grade = 2;
        //    }
        //    else if(MyInfo.Instance.Score > 1300)
        //    {
        //        Grade = 3;
        //    }

        //    if (GUI.Button(new Rect(130f, 30f * buttonSizeMultipier, 150 * buttonSizeMultipier, 30 * buttonSizeMultipier), MyInfo.Instance.Score.ToString() + " - " + Grade.ToString()))
        //    {
        //        xmppCli.SendMyPresence();
        //    }
        //}
    }*/

    //public static void Test()
    //{
    //    IQ iq = new IQ(IqType.get);

    //    //<iq id="agsXMPP_4" type="get"><query xmlns="jabber:iq:roster" /></iq>
    //    agsXMPP.Xml.Dom.Element query = new agsXMPP.Xml.Dom.Element("query");
    //    query.SetAttribute("xmlns", "jabber:iq:last");
    //    iq.Query = query;
    //    iq.Id = agsXMPP.Id.GetNextId();

    //    Debug.LogError("xmppCli - Send -- " + iq.ToString());
    //    xmppCli.Send(iq);
    //}

    public bool NeedToRegisterAccount = false;

    public void RequestSubscribePresence(int UserDBID)
    {
        Jid To = new Jid(UserDBID.ToString(), xmppCli.Server, xmppCli.Resource);
        xmppCli.PresenceManager.Subscribe(To);
    }

    public void RequestUnsubscribePresence(int UserDBID)
    {
        Jid To = new Jid(UserDBID.ToString(), xmppCli.Server, xmppCli.Resource);
        xmppCli.PresenceManager.Unsubscribe(To);
    }

    public PresenceStatus GetPresence(int UserDBID)
    {
        if (!FriendsPresenceMap.ContainsKey(UserDBID))
        {
            lock (FriendsPresenceMap)
            {
                FriendsPresenceMap.Add(UserDBID, PresenceStatus.OFFLINE);
            }
        }

        return FriendsPresenceMap[UserDBID];
    }

    public void RefreshPresence()
    {
        xmppCli.SendMyPresence();
    }
}
